//lobby.cc

#include "cineplex.h"


Lobby::Lobby(char* name)
{
	myName = name;
	msgList = new MsgList();
	msgLock = new Lock(myName);
	state = "Idling";
	sleepCon = new Condition(myName);
	
	custInLobby = new IterList();
	custToAsk = new IterList();
}

Lobby::~Lobby()
{
	delete custInLobby;
	delete custToAsk;	
}

void
Lobby::Start()
{
	printf("Starting lobby %s...\n", myName);
	cinema = getCineplex();
	if(getCineplex()->runSchedulers) Scheduler();
}

void
Lobby::SendMessage(char* name, int argc, ...)
{
	msgLock->Acquire();
	
	//printf("Lobby %s rec msg \"%s\"\n",myName,name);
	
	IterList* args = new IterList();
	va_list vali;
	va_start(vali, argc);
	
	for ( int i = 0; i < argc; i++ )        
    {
        args->Append(va_arg ( vali, void* )); 
    }
	va_end(vali);
	
	msgList->Append(name, args);
	sleepCon->Signal(msgLock);
	
	msgLock->Release();
}

void
Lobby::SendMessage(char* name, IterList* args)
{
	msgLock->Acquire();
	
	msgList->Append(name, args);
	sleepCon->Signal(msgLock);
	
	msgLock->Release();
}

void
Lobby::Scheduler()
{
	int runScheduler = getCineplex()->runSchedulers;
	do
	{
		//printf("%s running Scheduler...\n",myName);
		if(!strcmp(state,"Idling"))
		{
			IdleAction();
		}else if(!strcmp(state,"StartReleasing"))
		{
			StartReleasing();
		}else if(!strcmp(state,"AskCount"))
		{
			AskCount();
		}else if(!strcmp(state,"WaitCount"))
		{
			WaitCount();
		}else if(!strcmp(state,"WaitForTech"))
		{
			WaitForTech();
		}
	} while(runScheduler);
}

void
Lobby::IdleAction()
{
	msgLock->Acquire();
	IterList* custMsg = msgList->Find("IAmInLobby");
	if(custMsg)
	{	
		printf("Adding customer to lobby\n");
		custInLobby->Append(custMsg->Get(0));
		msgLock->Release();
	}else{
		IterList* manMsg = msgList->Find("NewMovieStarting");
		if(manMsg)
		{
			state = "StartReleasing";
			msgLock->Release();
		}else{
			msgLock->Release();
			WaitForTech(); //since state isn't set to wait, this will answer the msg if sent, sleep normally otherwise
			//sleepCon->Wait(msgLock);
		}
	}
}

void
Lobby::StartReleasing()
{
	custInLobby->AppendMeTo(custToAsk);
	//printf("Releasing lobby - %d groups\n", custToAsk->getSize());
	state = "AskCount";
	repliesWaiting = custToAsk->getSize();
}

void
Lobby::AskCount()
{
	if(custToAsk->IsEmpty()) state = "WaitCount";
	else
	{	
		custInLobby->Pop(0);
		replyTo = custToAsk->Pop(0);
		printf("%s requesting size from %s\n",myName,((Customer*)replyTo)->myName);
		((Customer*)replyTo)->SendMessage("HowManyInYourGroup",1,this);
	}
}

void
Lobby::WaitCount()
{
	if(repliesWaiting == 0)
	{
		state = "WaitForTech";
		return;
	}
	msgLock->Acquire();
	IterList* custMsg = msgList->Find("WeAreLegion");
	if(custMsg)
	{
		msgLock->Release();
		replyTo = custMsg->Get(0);
		msgInt = custMsg->GetInt(1);
		//printf("%s acquiring seating lock\n", myName);
		cinema->theater->seatingLock->Acquire();
		//printf("%s acquired seating lock\n", myName);
		repliesWaiting = repliesWaiting - 1;
		if(cinema->theater->totalSeats - cinema->theater->seatsFilled > msgInt)
		{
			((Customer*)replyTo)->SendMessage("LeaveLobby",0);
			printf("%s Releasing %s with size %d\n",myName,((Customer*)replyTo)->myName, msgInt);
			cinema->theater->seatingLock->Release();
			//state = "AskCount";
		}else
		{
			printf("%s NOT Releasing %s with size %d\n",myName,((Customer*)replyTo)->myName, msgInt);
			custInLobby->Append((Customer*)replyTo);
			cinema->theater->seatingLock->Release();
			//state = "AskCount";
		}
	}else{
		msgLock->Release();
		sleepCon->Wait(msgLock);
	}
}

void
Lobby::WaitForTech()
{
	msgLock->Acquire();
	IterList* techMsg = msgList->Find("AreYouIdle");
	if(techMsg)
	{
		msgLock->Release();
		replyTo = techMsg->Get(0);
		//printf("%s telling %s lobby is done\n",myName,((MovieTech*)replyTo)->myName);
		((MovieTech*)replyTo)->SendMessage("LobbyEmpty",0);
		state = "Idling";
	}else{
		msgLock->Release();
		//printf("~~~lobby sleeping~~~\n");
		sleepCon->Wait(msgLock);
		//printf("~~~lobby waking~~~\n");
	}
}
